'''
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with self work for additional information
 * regarding copyright ownership.  The ASF licenses self file
 * to you under the Apache License, Version 2.0 (the
 * "License") you may not use self file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http:#www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
'''
from base.graph.Triple import Triple
from base.rdf.Literal import Literal
from base.rdf.LiteralRequiredException import LiteralRequiredException
from base.rdf.Statement import Statement
from base.rdf.impl.LiteralImpl import LiteralImpl
from base.rdf.impl.PropertyImpl import PropertyImpl
from base.rdf.impl.ResourceImpl import ResourceImpl
from base.rdf.impl.StatementBase import StatementBase

#import org.apache.jena.enhanced.*;
#import org.apache.jena.graph.*;
#import org.apache.jena.rdf.model.*;

'''
 * An implementation of Statement.
'''
class StatementImpl(StatementBase, Statement):

    # protected Resource subject
    # protected Property predicate
    # protected RDFNode obj

    '''
     * Creates StatementImpl
    '''
    # param Resource subject, Property predicate, RDFNode obj, ModelCom model
    def __init__(self, subject, predicate, obj, model):
        super().__init__(model)
        self.subject = subject.inModel(model)
        self.predicate = predicate.inModel(model)
        self.obj = obj.inModel(model)
    

    # param 
    # result static ModelCom empty = ModelFactory.createDefaultModel(self)
    from base.rdf.ModelFactory import ModelFactory
    empty = ModelFactory.createDefaultModel()

    # param Resource subject, Property predicate, RDFNode obj
    def initWithSPO(self, subject, predicate, obj):
        super().__init__(self.empty)
        self.subject = subject.inModel(self.model)
        self.predicate = predicate.inModel(self.model)
        self.obj = obj.inModel(self.model)
    

    '''
     * create a Statement from the triple _t_ in the enhanced graph _eg_. The
     * Statement has subject, predicate, and obj corresponding to those of
     * _t_.
    '''
    # param Triple t, ModelCom eg
    # result static Statement
    @staticmethod
    def toStatement(t, eg):
        # Resource
        s = ResourceImpl().initWithNodeAndModelCom(t.getSubject(), eg)
        # Property
        p = PropertyImpl().initWithNodeAndEnhGraph(t.getPredicate(), eg)
        # RDFNode
        o = StatementImpl.createObject(t.getObject(), eg)
        return StatementImpl(s, p, o, eg)
    

    # @Override
    # param 
    # result Resource
    def getSubject(self):
        return self.subject
    

    # @Override
    # param 
    # result Property
    def getPredicate(self):
        return self.predicate
    

    # @Override
    # param 
    # result RDFNode
    def getObject(self):
        return self.obj
    

    # @Override
    # param Property p
    # result Statement
    def getStatementProperty(self, p):
        return self.asResource().getRequiredProperty(p)
    

    # @Override
    # param 
    # result Resource
    def getResource(self):
        return self.mustBeResource(self.obj)
    

    # @Override
    # @Deprecated
    # param ResourceF f
    # result Resource
    def getResourceWithFactory(self, f):
        return f.createResource(self.getResource())
    

    # @Override
    # param Property p
    # result Statement
    def getProperty(self, p):
        return self.getResource().getRequiredProperty(p)
    

    '''
     * get the obj field of self statement, insisting that it be a Literal.
     * If it isn't, throw LiteralRequiredException.
    '''
    # @Override
    # param 
    # result Literal
    def getLiteral(self):
        if isinstance(self.obj, Literal):
            return self.obj
        else:
            raise LiteralRequiredException(self.obj)
        
    
    # TODO as方法后续需要研究
    # @Override
    # param 
    # result Bag
    # def getBag(self):
    #     return self.obj.as(Bag.class)
    #
    #
    # # @Override
    # # param
    # # result Alt
    # def getAlt(self):
    #     return self.obj.as(Alt.class)
    #
    #
    # # @Override
    # # param
    # # result Seq
    # def getSeq(self):
    #     return self.obj.as(Seq.class)
    #
    #
    # # @Override
    # # param
    # # result RDFList
    # def getList(self):
    #     return self.obj.as(RDFList.class)
    

    '''
     * it turns out to be handy to return the StatementImpl as the result
    '''
    # @Override
    # param RDFNode n
    # result StatementImpl
    def replace(self, n):
        # StatementImpl
        s = StatementImpl(self.subject, self.predicate, n, self.model)
        self.model.remove(self).add(s)
        return s
    

    '''
     * .equals() defers to .sameAs so we only get the complexity of one cast.
    '''
    # @Override
    # param obj o
    # result boolean
    def equals(self, o):
        return isinstance(o, Statement) and self.sameAs(o)
    

    '''
     * sameAs - is self statement equal to the statement o? We can't assume
     * o is a StatementImpl
    '''
    # param Statement o
    # result final boolean
    def sameAs(self, o):
        return self.subject.equals(o.getSubject()) and self.predicate.equals(o.getPredicate()) and self.obj.equals(o.getObject())
    

    # @Override
    # param 
    # result int
    def hashCode(self):
        return self.asTriple().hashCode()
    

    # param 
    # result Resource
    def asResource(self):
        return self.model.getAnyReifiedStatement()
    

    # @Override
    # param 
    # result Statement
    def remove(self):
        self.model.remove(self)
        return self
    

    # @Override
    # param 
    # result void
    def removeReification(self):
        self.model.removeAllReifications(self)
    

    # @Override
    # param 
    # result Triple
    def asTriple(self):
        return Triple.create(self.subject.asNode(), self.predicate.asNode(), self.obj.asNode())
    

    '''
     * returns an array of triples corresponding to the array of statements ie
     * the i'th element of the result is the i'th element of the input as a triple.
     *
     * @param statements the array of statements to convert
     * @return the corresponding array of triples
    '''
    # param Statement[] statements
    # result static Triple[]
    def asTriples(self, statements):
        # Triple[]
        # triples = Triple[statements.length]
        triples = [None for _ in range(0, len(statements))]
        for i in range(0, len(statements)):
            triples[i] = statements[i].asTriple()
        return triples
    

    # @Override
    # param 
    # result boolean
    # def isReified(self):
    #     return self.model.isReified(self)
    

    '''
     * create a ReifiedStatement corresponding to self Statement
    '''
    # @Override
    # param 
    # result ReifiedStatement
    # def createReifiedStatement(self):
    #     return ReifiedStatementImpl.create(self)
    

    '''
     * create a ReifiedStatement corresponding to self Statement
     * and with the given _uri_.
    '''
    # @Override
    # param String uri
    # result ReifiedStatement
    # def createReifiedStatement(self, uri):
    #     return ReifiedStatementImpl.create((ModelCom) self.getModel(), uri, self)
    

    # @Override
    # param 
    # result RSIterator
    # def listReifiedStatements(self):
    #     return model.listReifiedStatements(self)
    

    '''
     * create an RDF node which might be a literal, or not.
    '''
    # param Node n, EnhGraph g
    # result static RDFNode
    @staticmethod
    def createObject(n, g):
        return LiteralImpl(n, g) if n.isLiteral() else ResourceImpl().initWithNodeAndEnhGraph(n, g)
    


